今天繼續介紹應用指令的參數,會著重在如何避免使用者輸入不合適的參數。
這應該算是應用指令的最後一篇了...
相信各位程式開發者應該都有這樣的經驗:開發了一個功能,但偏偏使用者並不按照原本設想的方式使用,
因此,開發者往往都需要盡量設想各種可能,並且做出對應的防範措施。而可以讓使用者自行設定參數的斜線指令也是如此,開發者需要防範使用者輸入不合適的參數。
在昨天的文章有提到,如果使用者輸入的型別不正確,就會出現錯誤提示,提醒使用者要輸入正確的格式 (例如:請輸入有效的整數)。但有時候,光是型別還不夠,因此,接下來會介紹更多限制的方法,包含:
如果參數的選項不多,直接把所有選項都設定好,並要求使用者只能從中選一個,會是一個很好的選擇。而設定選項的方式也有幾種不同的寫法:
最簡單的就是使用 Literal
,將所有選項列出來。
from typing import Literal
# ...
@client.tree.command(description="點餐")
async def order(
interaction: discord.Interaction,
tea: Literal["綠茶", "紅茶", "奶茶"],
size: Literal["大杯", "中杯", "小杯"],
):
await interaction.response.send_message(f"點餐結果:{tea}{size}")
# ...
之後設定參數時,就只能從上面所列的選項中進行選擇了。
除了 Literal
,也可以使用 Enum
。使用 Enum
除了可以更方便管理這些常數們,也可以做成 key、value 對,讓程式可以依據需求選擇要使用的值。
from enum import Enum
# ...
class Tea(Enum):
green_tea = "綠茶"
black_tea = "紅茶"
milk_tea = "奶茶"
class Size(Enum):
small = "小杯"
medium = "中杯"
large = "大杯"
@client.tree.command(description="點餐")
async def order(
interaction: discord.Interaction,
tea: Tea,
size: Size,
):
await interaction.response.send_message(f"點餐結果:{tea.value}{size.value}")
# ...
這邊顯示的選項就會是英文,函數內再用 .value
來取得中文。
不過,由於 Enum
本身寫法上的限制,很難反過來改成顯示中文選項,但取得英文的值。想要做到的話,就可以考慮使用下一個方法:choice
。
直接來看範例。
from discord.app_commands import Choice
# ...
@client.tree.command(description="點餐")
@app_commands.choices(tea=[
Choice(name='綠茶', value='green_tea'),
Choice(name='紅茶', value='black_tea'),
Choice(name='奶茶', value='milk_tea'),
])
@app_commands.choices(size=[
Choice(name='小杯', value='small'),
Choice(name='中杯', value='medium'),
Choice(name='大杯', value='large'),
])
async def order(
interaction: discord.Interaction,
tea: Choice[str],
size: Choice[str],
):
await interaction.response.send_message(f"點餐結果:{tea.name}{size.name}")
# ...
這個範例還是一樣回傳中文,但如果需要取得英文,改用 .value
取值就好。
在某些時候,要把所有選項列出來並不容易 (例如:飲料的杯數),但如果選項是在某個範圍內的數字的話,就可以使用 Range
。
來看一下這個範例:
from discord.app_commands import Range
# ...
@client.tree.command(description="點餐")
async def order(
interaction: discord.Interaction,
tea: Literal["綠茶", "紅茶", "奶茶"],
size: Literal["大杯", "中杯", "小杯"],
number: Range[int, 1, 10],
):
await interaction.response.send_message(f"點餐結果:{tea}{size} {number}杯")
# ...
執行後,在輸入數量前,並沒有提示:
但按下 Enter 送出後,就會跳出錯誤提示,要求必須在範圍內才可以。
Range
的用法有幾種不同的變化:
Range[int, 10]
表示最小值是 10,沒有上限。Range[int, None, 10]
表示最大值是 10,沒有下限。Range[int, 1, 10]
表示最小值是 1,最大值是 10。Range[float, 1.0, 5.0]
表示最小值是 1.0,最大值是 5.0。Range[str, 1, 10]
表示最小長度是 1,最大長度是 10。今天算是「暫時」把應用指令收尾了,明天會介紹 bot 指令框架,把目前的觸發條件、應用指令等的寫法重新包裝。
今天是 PyCon 第二天,有幾個跟 FastAPI 相關的演講,感覺格外親切 XD